////////////////////////////////////////////////////////////////////////////////
// (c) 2012 Rolf Meyerhoff. All rights reserved.
////////////////////////////////////////////////////////////////////////////////
///\file    mainmidiwindow.h
///\ingroup dtedit
///\brief   Main window with MIDI class definition.
///\author  Rolf Meyerhoff (badlantic@gmail.com)
///\version 1.0
/// This file is part of the DT editor.
////////////////////////////////////////////////////////////////////////////////
///\par License:
/// This program is free software: you can redistribute it and/or modify it
/// under the terms of the GNU General Public License as published by the Free
/// Software Foundation, either version 2 of the License, or (at your option)
/// any later version.
///\par
/// This program is distributed in the hope that it will be useful, but WITHOUT
/// ANY WARRANTY; without even  the implied warranty of MERCHANTABILITY or
/// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
/// more details.
///\par
/// You should have received a copy of the GNU General Public License along with
/// this program; see the file COPYING. If not, see http://www.gnu.org/licenses/
/// or write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
/// Floor, Boston, MA 02110-1301, USA.
////////////////////////////////////////////////////////////////////////////////
#ifndef __MAINMIDIWINDOW_H_INCLUDED__
#define __MAINMIDIWINDOW_H_INCLUDED__

#include <QtGui>
#if QT_VERSION >= 0x050000
#include <QtWidgets>
#endif
#include "RtMidi/RtMidi.h"

////////////////////////////////////////////////////////////////////////////////
///\class MainMIDIWindow mainmidiwindow.h
///\brief Main window class with MIDI support.
/// This is a main window class that adds a MIDI input and output to the window.
////////////////////////////////////////////////////////////////////////////////
class MainMIDIWindow :
  public QMainWindow
{
  Q_OBJECT // Qt magic...

public:
  //////////////////////////////////////////////////////////////////////////////
  // MainMIDIWindow::MainMIDIWindow()
  //////////////////////////////////////////////////////////////////////////////
  ///\brief   Initialization constructor of this window.
  ///\param   [in] parent: Parent window for this window.
  ///\remarks Basically initializes the entire gui.
  //////////////////////////////////////////////////////////////////////////////
  MainMIDIWindow(QWidget* parent = 0);

  //////////////////////////////////////////////////////////////////////////////
  // MainMIDIWindow::~MainMIDIWindow()
  //////////////////////////////////////////////////////////////////////////////
  ///\brief   Destructor of this window.
  ///\remarks Choose! Choose the form of the Destructor!
  //////////////////////////////////////////////////////////////////////////////
  ~MainMIDIWindow();

protected:
  //////////////////////////////////////////////////////////////////////////////
  // MainMIDIWindow::openMIDIPorts()
  //////////////////////////////////////////////////////////////////////////////
  ///\brief   Open the MIDI devices for input/output.
  ///\return  Returns true if successfull or false otherwise.
  ///\remarks Always closes the port priot trying to open them again.
  //////////////////////////////////////////////////////////////////////////////
  virtual bool openMIDIPorts();

  //////////////////////////////////////////////////////////////////////////////
  // MainMIDIWindow::showSetupWindow()
  //////////////////////////////////////////////////////////////////////////////
  ///\brief   Show the configuration dialog.
  ///\return  Returns true if successfull or false otherwise.
  ///\remarks A false return value means that the user pressed cancel.
  //////////////////////////////////////////////////////////////////////////////
  virtual bool showSetupWindow();

  //////////////////////////////////////////////////////////////////////////////
  // MainMIDIWindow::noteOnReceived()
  //////////////////////////////////////////////////////////////////////////////
  ///\brief   This is called when a new note on message arrives.
  ///\param   [in] channel:    MIDI channel of this message.
  ///\param   [in] noteNumber: Note number.
  ///\param   [in] velocity:   Note velocity.
  //////////////////////////////////////////////////////////////////////////////
  virtual void noteOnReceived(unsigned char channel, unsigned char noteNumber, unsigned char velocity);

  //////////////////////////////////////////////////////////////////////////////
  // MainMIDIWindow::noteOffReceived()
  //////////////////////////////////////////////////////////////////////////////
  ///\brief   This is called when a new note off message arrives.
  ///\param   [in] channel:    MIDI channel of this message.
  ///\param   [in] noteNumber: Note number.
  ///\param   [in] velocity:   Note velocity.
  //////////////////////////////////////////////////////////////////////////////
  virtual void noteOffReceived(unsigned char channel, unsigned char noteNumber, unsigned char velocity);

  //////////////////////////////////////////////////////////////////////////////
  // MainMIDIWindow::controlChangeReceived()
  //////////////////////////////////////////////////////////////////////////////
  ///\brief   This is called when a new control change message arrives.
  ///\param   [in] channel:       MIDI channel of this message.
  ///\param   [in] controlNumber: Controller number.
  ///\param   [in] value:         Control value.
  //////////////////////////////////////////////////////////////////////////////
  virtual void controlChangeReceived(unsigned char channel, unsigned char controlNumber, unsigned char value);

  //////////////////////////////////////////////////////////////////////////////
  // MainMIDIWindow::programChangeReceived()
  //////////////////////////////////////////////////////////////////////////////
  ///\brief   This is called when a new program change message arrives.
  ///\param   [in] channel: MIDI channel of this message.
  ///\param   [in] value:   Program number.
  //////////////////////////////////////////////////////////////////////////////
  virtual void programChangeReceived(unsigned char channel, unsigned char value);

  //////////////////////////////////////////////////////////////////////////////
  // MainMIDIWindow::channelAftertouchReceived()
  //////////////////////////////////////////////////////////////////////////////
  ///\brief   This is called when a new channel aftertouch message arrives.
  ///\param   [in] channel: MIDI channel of this message.
  ///\param   [in] value:   Pressure value.
  //////////////////////////////////////////////////////////////////////////////
  virtual void channelAftertouchReceived(unsigned char channel, unsigned char value);

  //////////////////////////////////////////////////////////////////////////////
  // MainMIDIWindow::pitchBendReceived()
  //////////////////////////////////////////////////////////////////////////////
  ///\brief   This is called when a new pitch bend message arrives.
  ///\param   [in] channel: MIDI channel of this message.
  ///\param   [in] value:   Pitch bend value.
  //////////////////////////////////////////////////////////////////////////////
  virtual void pitchBendReceived(unsigned char channel, unsigned short value);

  //////////////////////////////////////////////////////////////////////////////
  // MainMIDIWindow::polyAftertouchReceived()
  //////////////////////////////////////////////////////////////////////////////
  ///\brief   This is called when a new poly pressure message arrives.
  ///\param   [in] channel:    MIDI channel of this message.
  ///\param   [in] noteNumber: Note number.
  ///\param   [in] value:      Pressure value.
  //////////////////////////////////////////////////////////////////////////////
  virtual void polyAftertouchReceived(unsigned char channel, unsigned char noteNumber, unsigned char value);

  //////////////////////////////////////////////////////////////////////////////
  // MainMIDIWindow::sysExReceived()
  //////////////////////////////////////////////////////////////////////////////
  ///\brief   This is called when a new SysEx message arrives.
  ///\param   [in] buff: The message buffer.
  ///\param   [in] value:      Pressure value.
  //////////////////////////////////////////////////////////////////////////////
  virtual void sysExReceived(const std::vector<unsigned char>& buff);

  //////////////////////////////////////////////////////////////////////////////
  // MainMIDIWindow::sendNoteOn()
  //////////////////////////////////////////////////////////////////////////////
  ///\brief   Send a note on message.
  ///\param   [in] channel:    MIDI channel of this message.
  ///\param   [in] noteNumber: Note number.
  ///\param   [in] velocity:   Note velocity.
  //////////////////////////////////////////////////////////////////////////////
  virtual void sendNoteOn(unsigned char channel, unsigned char noteNumber, unsigned char velocity);

  //////////////////////////////////////////////////////////////////////////////
  // MainMIDIWindow::sendNoteOff()
  //////////////////////////////////////////////////////////////////////////////
  ///\brief   Send a note off message.
  ///\param   [in] channel:    MIDI channel of this message.
  ///\param   [in] noteNumber: Note number.
  ///\param   [in] velocity:   Note velocity.
  //////////////////////////////////////////////////////////////////////////////
  virtual void sendNoteOff(unsigned char channel, unsigned char noteNumber, unsigned char velocity);

  //////////////////////////////////////////////////////////////////////////////
  // MainMIDIWindow::sendControlChange()
  //////////////////////////////////////////////////////////////////////////////
  ///\brief   Send a control change message.
  ///\param   [in] channel:       MIDI channel of this message.
  ///\param   [in] controlNumber: Control number.
  ///\param   [in] value:         Control value.
  //////////////////////////////////////////////////////////////////////////////
  virtual void sendControlChange(unsigned char channel, unsigned char controlNumber, unsigned char value);

  //////////////////////////////////////////////////////////////////////////////
  // MainMIDIWindow::sendProgramChange()
  //////////////////////////////////////////////////////////////////////////////
  ///\brief   Send a program change message.
  ///\param   [in] channel: MIDI channel of this message.
  ///\param   [in] value:   Program number.
  //////////////////////////////////////////////////////////////////////////////
  virtual void sendProgramChange(unsigned char channel, unsigned char value);

  //////////////////////////////////////////////////////////////////////////////
  // MainMIDIWindow::sendChannelAftertouch()
  //////////////////////////////////////////////////////////////////////////////
  ///\brief   Send a channel aftertouch message.
  ///\param   [in] channel: MIDI channel of this message.
  ///\param   [in] value:   Pressure value.
  //////////////////////////////////////////////////////////////////////////////
  virtual void sendChannelAftertouch(unsigned char channel, unsigned char value);

  //////////////////////////////////////////////////////////////////////////////
  // MainMIDIWindow::sendPitchBend()
  //////////////////////////////////////////////////////////////////////////////
  ///\brief   Send a pitch bend message.
  ///\param   [in] channel: MIDI channel of this message.
  ///\param   [in] value:   Pitch bend value.
  //////////////////////////////////////////////////////////////////////////////
  virtual void sendPitchBend(unsigned char channel, unsigned short value);

  //////////////////////////////////////////////////////////////////////////////
  // MainMIDIWindow::sendPolyAftertouch()
  //////////////////////////////////////////////////////////////////////////////
  ///\brief   Send a poly aftertouch message.
  ///\param   [in] channel:    MIDI channel of this message.
  ///\param   [in] noteNumber: Note number.
  ///\param   [in] value:      Pressure value.
  //////////////////////////////////////////////////////////////////////////////
  virtual void sendPolyAftertouch(unsigned char channel, unsigned char noteNumber, unsigned char value);

  //////////////////////////////////////////////////////////////////////////////
  // MainMIDIWindow::onMIDIMessage()
  //////////////////////////////////////////////////////////////////////////////
  ///\brief   Callback for incoming MIDI messages.
  ///\param   [in] timeStamp: Time stamp of the message.
  ///\param   [in] message:   The raw MIDI message as byte buffer.
  ///\remarks Updates the surface depending on the MIDI data.
  //////////////////////////////////////////////////////////////////////////////
  virtual void onMIDIMessage(const double timeStamp, const std::vector<unsigned char>& message);

  ////////////////////////////////////////////////////////////////////////////////
  // MainMIDIWindow::Sleep()
  ////////////////////////////////////////////////////////////////////////////////
  ///\brief   Helper function to make the current thread sleep a while.
  ///\param   [in] milliSeconds: Number of milliseconds to sleep.
  ////////////////////////////////////////////////////////////////////////////////
  static void Sleep(int milliSeconds);

  //////////////////////////////////////////////////////////////////////////////
  // Member:
  QString   midiInName;  ///> Name of the active MIDI input.
  QString   midiOutName; ///> Name of the active MIDI output.
  bool      midiOK;      ///> Is the MIDI system up and running?
  RtMidiIn  midiIn;      ///> The MIDI input used.
  RtMidiOut midiOut;     ///> The MIDI output used.

private:

  //////////////////////////////////////////////////////////////////////////////
  // MainMIDIWindow::onMIDIMessageProxy()
  //////////////////////////////////////////////////////////////////////////////
  ///\brief   Callback for incoming MIDI messages.
  ///\param   [in] timeStamp: Time stamp of the message.
  ///\param   [in] message:   The raw MIDI message as byte buffer.
  ///\param   [in] userData:  User data set when the port was created.
  ///\remarks The userData holds a pointer to this class so this function
  ///         delegates the call to the member function of the class.
  //////////////////////////////////////////////////////////////////////////////
  static void onMIDIMessageProxy(double timeStamp, std::vector<unsigned char>* message, void* userData);
};

#endif // #ifndef __MAINMIDIWINDOW_H_INCLUDED__
///////////////////////////////// End of File //////////////////////////////////
